package org.hackystat.ui.telemetryviewer.gwt.client;

import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * The container for the dependency chart, it encapsulates all internals into one easy managable
 * widget.
 *
 * @author Pavel Senin.
 *
 */
public class ChartDependency
    extends ChartWidget {

  /* the chart image holder */
  final ChartImageWidget chartImage;

  /* the series flags show these by default */
  boolean afferentCouplings = true;
  boolean efferentCouplings = true;
  boolean cycles = true;

  /* the initial span */
  private String timeSpan = "7d";

  /* delimeter to use in queries */
  static final char delimiter = '#';

  /* label widget used for debugging */
  static final Label label = new Label("clientRequest");

  static final Label label2 = new Label("serverResponse");

  static final String trickyStyleName = "chart-SpanWidget";

  /**
   * Creates an instance and reports a handler.
   *
   * @return the widget handler.
   */
  public static ChartHandler init() {
    return new ChartHandler("Dependency", "Dependency analysis") {
      public ChartWidget createInstance() {
        return new ChartDependency();
      }
    };
  }

  /**
   * Creates the object and initializes all of the internal widgets.
   *
   */
  public ChartDependency() {

    /* instantiating the description widget */
    HTML description = new HTML("Each of the software development projects should care about "
        + "dependencies. All you need is to attach JDepend or DependencyFinder tool to your "
        + "Ant scripts and monitor dependencies using such a nice system as HackyStat.<br>"
        + "This mockup uses random data to generate plots and hacked with purpose to "
        + "find the way of employing GWT in the future HackyStat ver.8 system.<br>"
        + "There are two widgets: Range selection and Series selection which change the picture.",
        true);
    description.setStyleName("chart-InfoWidget");

    /* instantiating span selection widget */
    final SpanRangeWidget spanRange = new SpanRangeWidget(this);
    loadSpans(spanRange);

    /* instantiating chart widget */
    chartImage = new ChartImageWidget("dependency#7d#true#true#true");
    chartImage.setStyleName("chart-Image");

    /* instantiating series selection widget */
    final TelemetrySelectionWidget seriesSelection = new TelemetrySelectionWidget(this);
    loadSeries(seriesSelection);

    /* adding all this stuff to the root panel */
    VerticalPanel mainLayoutPanel = new VerticalPanel();
    mainLayoutPanel.setVerticalAlignment(VerticalPanel.ALIGN_TOP);
    mainLayoutPanel.setSpacing(0);
    mainLayoutPanel.setStyleName("chart-DependencyPanel");

    // add description
    mainLayoutPanel.add(description);

    VerticalPanel allWidgetsPanel = new VerticalPanel();
    allWidgetsPanel.setStyleName(trickyStyleName);

    // add the span menu
    HorizontalPanel hpSpan = new HorizontalPanel();
    hpSpan.add(spanRange);
    hpSpan.setStyleName(trickyStyleName);
    allWidgetsPanel.add(hpSpan);

    // add the chart widget
    HorizontalPanel hpChart = new HorizontalPanel();
    hpChart.add(chartImage);
    hpChart.setStyleName(trickyStyleName);
    allWidgetsPanel.add(hpChart);

    // add the series menu
    HorizontalPanel hpSeries = new HorizontalPanel();
    hpSeries.add(seriesSelection);
    hpSeries.setStyleName(trickyStyleName);
    allWidgetsPanel.add(hpSeries);

    // add the dummy debugG
    label.setStyleName("dummyDebugLabel");
    label.setText("Client request: \"dependency#7d#true#true#true\"");
    HorizontalPanel hpDebugLabel = new HorizontalPanel();
    hpDebugLabel.add(label);
    hpDebugLabel.setStyleName(trickyStyleName);

    allWidgetsPanel.add(hpDebugLabel);

    // add the dummy debugG #2
    label2.setStyleName("dummyDebugLabel");
    label2.setText("serverResponse:");
    HorizontalPanel hpDebugLabel2 = new HorizontalPanel();
    hpDebugLabel2.add(label2);
    hpDebugLabel2.setStyleName(trickyStyleName);

    allWidgetsPanel.add(hpDebugLabel2);

    mainLayoutPanel.add(allWidgetsPanel);

    initWidget(mainLayoutPanel);

  }

  /**
   * Adds all the telemetry series into the Series panel.
   *
   * @param seriesSelection the list widget which would hold all added series.
   */
  private void loadSeries(TelemetrySelectionWidget seriesSelection) {

    CheckBox cb = new CheckBox("AfferentCouplings");
    cb.setChecked(true);
    // Hook up a listener to find out when it's clicked.
    cb.addClickListener(new ClickListener() {
      public void onClick(Widget sender) {
        if (((CheckBox) sender).isChecked()) {
          updateChart(null, "AfferentCouplings");
        }
        else {
          updateChart(null, "NoAfferentCouplings");
        }
      }
    });
    seriesSelection.addSeries(cb);

    cb = new CheckBox("EfferentCouplings");
    cb.setChecked(true);
    // Hook up a listener to find out when it's clicked.
    cb.addClickListener(new ClickListener() {
      public void onClick(Widget sender) {
        if (((CheckBox) sender).isChecked()) {
          updateChart(null, "EfferentCouplings");
        }
        else {
          updateChart(null, "NoEfferentCouplings");
        }
      }
    });
    seriesSelection.addSeries(cb);

    cb = new CheckBox("Cycles");
    cb.setChecked(true);
    // Hook up a listener to find out when it's clicked.
    cb.addClickListener(new ClickListener() {
      public void onClick(Widget sender) {
        if (((CheckBox) sender).isChecked()) {
          updateChart(null, "Cycles");
        }
        else {
          updateChart(null, "NoCycles");
        }
      }
    });
    seriesSelection.addSeries(cb);

  }

  /**
   * Adds all the available spans into the Spans panel.
   *
   * @param spanRange the list widget which would hold all added spans.
   */
  private void loadSpans(SpanRangeWidget spanRange) {

    SpanButton spb = new SpanButton("7d");
    spb.addClickListener(spanRange);
    spanRange.addSpan(spb);

    spb = new SpanButton("14d");
    spb.addClickListener(spanRange);
    spanRange.addSpan(spb);

    spb = new SpanButton("1m");
    spb.addClickListener(spanRange);
    spanRange.addSpan(spb);

    spb = new SpanButton("3m");
    spb.addClickListener(spanRange);
    spanRange.addSpan(spb);

    spb = new SpanButton("6m");
    spb.addClickListener(spanRange);
    spanRange.addSpan(spb);

    spb = new SpanButton("1y");
    spb.addClickListener(spanRange);
    spanRange.addSpan(spb);
  }

  /**
   * Update chart image when needed.
   *
   * @param span the chart parameters name.
   * @param series the optional parameters string.
   */
  public void updateChart(String span, String series) {

    // the case when span is not null
    if (null == span) {
      if ("EfferentCouplings".equals(series)) {
        this.efferentCouplings = true;
      }
      else if ("NoEfferentCouplings".equals(series)) {
        this.efferentCouplings = false;
      }
      else if ("AfferentCouplings".equals(series)) {
        this.afferentCouplings = true;
      }
      else if ("NoAfferentCouplings".equals(series)) {
        this.afferentCouplings = false;
      }
      else if ("Cycles".equals(series)) {
        this.cycles = true;
      }
      else if ("NoCycles".equals(series)) {
        this.cycles = false;
      }
      this.updateChartImage();
    }
    else {
      // the case when span is not null
      this.timeSpan = span;
      this.updateChartImage();
    }
  }

  /**
   * Makes a server request for the image by composes the request string and sending it through
   * asynchronous RPC call.
   *
   */
  public void updateChartImage() {

    final String request = "dependency" + ChartDependency.delimiter + this.timeSpan
        + ChartDependency.delimiter + this.afferentCouplings + ChartDependency.delimiter
        + this.efferentCouplings + ChartDependency.delimiter + this.cycles;

    chartImage.update(request);
    ChartDependency.label.setText("clientRequest: \"" + request + "\"");

    ChartDependency.label2.setText("serverResponse: \"" + chartImage.getLatestResponse() + "\"");
  }

  /** {@inheritDoc} */
  public void setSpan(String spn) {
    this.timeSpan = spn;
    updateChartImage();
  }
}
